﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using UnityEngine;
using Whoot.DI;

namespace Whoot
{
    public class Core
    {
        private readonly List<IBootstrap> _whootBootstrapList = new List<IBootstrap>();
        private readonly List<Type> _whootBootstrapTypeList = new List<Type>();

        #region instance and create

        private static Core _inst;
        private static object _lockObj = new object();
        private static bool _initDone = false;

        public static Core Inst
        {
            get
            {
                if (_initDone) return _inst;
                _inst = new Core();
                _initDone = true;
                return _inst;
            }
        }


        private Core()
        {
            _serviceContainer = new DiContainer();
        }

        #endregion

        
        #region 服务管理

        private readonly DiContainer _serviceContainer;
        private readonly List<IServiceProvider> _serviceProvidersList = new List<IServiceProvider>();
        
        /// <summary>
        /// 注册一个服务提供者
        /// </summary>
        /// <param name="provider"></param>
        public static void RegisterServiceProvider(IServiceProvider provider)
        {
            if (!Inst._serviceProvidersList.Contains(provider))
            {
                Inst._serviceProvidersList.Add(provider);
            }
        }

        /// <summary>
        /// 绑定服务
        /// </summary>
        /// <param name="userParams"></param>
        /// <typeparam name="TService"></typeparam>
        /// <typeparam name="TConcrete"></typeparam>
        public static void BindService<TService, TConcrete>(params object[] userParams)
            where TConcrete : TService, new()
        {
            Inst._serviceContainer.RegisterNew<TService, TConcrete>(userParams);
        }

        /// <summary>
        /// 绑定全局单例服务。
        /// </summary>
        /// <typeparam name="TService"></typeparam>
        /// <typeparam name="TConcrete"></typeparam>
        public static void BindSingletonService<TService, TConcrete>(params object[] userParams)
            where TConcrete : TService, new()
        {
            Inst._serviceContainer.RegisterNew<TService, TConcrete>(userParams).AsSingle();
        }

        /// <summary>
        /// 绑定内置服务
        /// </summary>
        /// <typeparam name="TBuiltInService"></typeparam>
        /// <typeparam name="TService"></typeparam>
        /// <typeparam name="TConcrete"></typeparam>
        public static void BindBuiltInService<TBuiltInService, TService, TConcrete>(params object[] userParams)
            where TConcrete : TService, new() where TBuiltInService : IBuiltInService
        {
            Inst._serviceContainer.RegisterNew<TService, TConcrete>(userParams).Alias<TBuiltInService>().AsSingle();
        }

        public static TService Get<TService>()
        {
            return (TService) Get(typeof(TService));
        }

        public static object Get(Type baseType)
        {
            return Inst._serviceContainer.Resolve(baseType);
        }

        public static bool HasSingleton<T>()
        {
            return Inst._serviceContainer.HasSingleton<T>();
        }

        /// <summary>
        /// 对传入的类进行依赖注入
        /// </summary>
        /// <param name="target"></param>
        public static void Inject(object target)
        {
            Inst._serviceContainer.Inject(target);
        }

        #endregion

        #region 异常处理

        /// <summary>
        /// 服务初始化失败的事件注册, string:service name 
        /// </summary>
        private Action<string, WhootException> _servicesInitExceptionAction;


        public static void OnServicesInitException(Action<string, WhootException> callback)
        {
            Inst._servicesInitExceptionAction += callback;
        }

        /// <summary>
        /// 服务启动失败的事件注册, string:service name 
        /// </summary>
        private Action<string, WhootException> _servicesStartExceptionAction;

        public static void OnServicesStartException(Action<string, WhootException> callback)
        {
            Inst._servicesStartExceptionAction += callback;
        }

        #endregion

        #region 启动

        /// <summary>
        /// 模块配置根目录
        /// </summary>
        public static string ConfigRootPath { get; private set; }

        public static bool ServiceConfigIsAb { get; private set; }

        /// <summary>
        /// 设置配置文件根目录
        /// </summary>
        public static void SetConfigRootPath(string path, bool isAb = false)
        {
            ConfigRootPath = path;
            ServiceConfigIsAb = isAb;
        }

        /// <summary>
        /// 设置启动入口
        /// </summary>
        /// <param name="inst"></param>
        public static void AddBootstrap<T>() where T : IBootstrap
        {
            Inst._whootBootstrapTypeList.Add(typeof(T));
        }


        private bool _inited = false;

        public static void Run()
        {
            Inst.RunNow();
        }

        private void RunNow()
        {
            if (_inited) return;

            if (ConfigRootPath == null || ConfigRootPath.Equals(string.Empty))
            {
                ConfigRootPath = "Config";
                ServiceConfigIsAb = false;
                Debug.LogWarning("未设置服务配置文件路径，将使用默认Resources/Config");
            }

            //对Service进行排序
            int GetServiceProviderOrder(ref IServiceProvider provider)
            {
                Type pType = provider.GetType();
                var attr = pType.GetCustomAttribute<ProviderOrderAttribute>();
                return attr?.Order ?? 99;
            }


            _serviceProvidersList.Sort((x, y) =>
                GetServiceProviderOrder(ref x).CompareTo(GetServiceProviderOrder(ref y)));

            //------------------触发Init阶段--------------------------------------------------------------

            //Invoke Services "Init"
            foreach (var service in _serviceProvidersList)
            {
                try
                {
                    service.OnInit();
                }
                catch (WhootException e)
                {
                    Debug.LogError(
                        $"[WhootFramework.Core] Exception when init xserver \"{service.ServiceName}\"");
                    if (_servicesInitExceptionAction != null &&
                        _servicesInitExceptionAction.GetInvocationList().Length > 0)
                        _servicesInitExceptionAction?.Invoke(service.ServiceName, e);
                    throw;
                }
            }

            foreach (var service in _serviceProvidersList)
            {
                service.OnServiceRegister();
            }

            //实例化启动入口
            foreach (var type in _whootBootstrapTypeList)
            {
                _whootBootstrapList.Add((IBootstrap) Activator.CreateInstance(type));
            }

            //Invoke IICBootstrap "Init"
            foreach (var item in _whootBootstrapList)
            {
                item.OnInit();
            }

            //------------------触发Start阶段----------------------------------------------------------------
            foreach (var service in _serviceProvidersList)
            {
                try
                {
                    service.OnStart();
                }
                catch (WhootException e)
                {
                    Debug.LogError(
                        $"[WhootFramework.Core] Exception when init xserver \"{service.ServiceName}\"");
                    if (_servicesStartExceptionAction != null &&
                        _servicesStartExceptionAction.GetInvocationList().Length > 0)
                        _servicesStartExceptionAction?.Invoke(service.ServiceName, e);
                    throw;
                }
            }
            
            Debug.Log("WhootFramework startup finish.");
            _inited = true;


            //Invoke ICBootstrap "Start"
            foreach (var xbs in _whootBootstrapList)
            {
                xbs.OnStart();
            }

            //调用程序入口
            Debug.Log("ICFramework App startup finish.");
        }

        #endregion
    }
}